import 'dart:async';

import 'package:rxdart/rxdart.dart';

import '../../common/test_page.dart';

class RetryTestPage extends TestPage {
  RetryTestPage(super.title) {
    test('Rx.retry', () async {
      const retries = 3;

      expect(Rx.retry(_getRetryStream(retries), retries));
    });

    test('RetryStream', () async {
      const retries = 3;

      expect(RetryStream<int>(_getRetryStream(retries), retries));
    });

    test('RetryStream.onDone', () async {
      const retries = 3;

      expect(RetryStream(_getRetryStream(retries), retries));
    });

    test('RetryStream.infinite.retries', () async {
      expect(RetryStream(_getRetryStream(1000)));
    });

    test('RetryStream.emits.original.items', () async {
      const retries = 3;

      expect(RetryStream(_getStreamWithExtras(retries), retries));
    });

    test('RetryStream.single.subscription', () async {
      const retries = 3;

      final stream = RetryStream(_getRetryStream(retries), retries);

      try {
        stream.listen(null);
        stream.listen(null);
      } catch (e) {
        expect(e);
      }
    });

    test('RetryStream.asBroadcastStream', () async {
      const retries = 3;

      final stream =
      RetryStream(_getRetryStream(retries), retries).asBroadcastStream();

      // listen twice on same stream
      stream.listen(null);
      stream.listen(null);
      // code should reach here
      expect(stream.isBroadcast);
    });

    test('RetryStream.error.shouldThrow', () async {
      final streamWithError = RetryStream(_getRetryStream(3), 2);

      expect(streamWithError);
    });

    test('RetryStream.error.capturesErrors', () {
      RetryStream(_getRetryStream(3), 2).listen(
        ((_) {}),
        onError: (
              (Object e, StackTrace st) {
            expect(e);
            expect(st);
          }
        ),
        onDone: (() {}),
      );
    });

    test('RetryStream.pause.resume', () async {
      late StreamSubscription<int> subscription;
      const retries = 3;

      subscription = RetryStream(_getRetryStream(retries), retries)
          .listen(((result) {
        expect(result);

        subscription.cancel();
      }));

      subscription.pause();
      subscription.resume();
    });
  }

}

Stream<int> Function() _getRetryStream(int failCount) {
  var count = 0;

  return () {
    if (count < failCount) {
      count++;
      return Stream<int>.error(Error(), StackTrace.fromString('S'));
    } else {
      return Stream.value(1);
    }
  };
}

Stream<int> Function() _getStreamWithExtras(int failCount) {
  var count = 0;

  return () {
    if (count < failCount) {
      count++;

      return Stream.value(1)
          .concatWith([Stream<int>.error(Error())])
          .concatWith([Stream.value(1)]);
    } else {
      return Stream.value(2);
    }
  };
}